package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.StringUtils;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @className: ResourceServiceImpl
 * @description:
 * @author: InnovatorX
 * @date: 2024/6/2 11:43
 * @Version: 1.0
 */
@Service
@Slf4j
public class ResourceServiceImpl implements ResourceService {
    @Autowired
    private ResourceMapper resourceMapper;

    @Autowired
//    private StringRedisTemplate stringRedisTemplate;
    private RedisTemplate<String, String> redisTemplate;

/*    @Override
    public List<ResourceVo> listResources(ResourceDto dto) {
//        if ((StringUtils.isBlank(dto.getResourceNo()))){
//            dto.setResourceNo(SuperConstant.ROOT_PARENT_ID);
//        }
//        if (StringUtils.isBlank(dto.getResourceType())){
//            dto.setResourceType(SuperConstant.MENU);
//        }
        // 访问redis
        String jsonStr = redisTemplate.opsForValue().get("resourceList");
        log.info("redis数据:{}", jsonStr);
        if (StringUtils.isNotBlank(jsonStr)) {
            log.info("redis数据不为空");
            List<ResourceVo> list = JSONUtil.toList(jsonStr, ResourceVo.class);
            // 如果有条件,就在集合中进行遍历找到集合条件的数据
//            List<ResourceVo> resultList = new ArrayList<>();
//            for (ResourceVo vo : list) {
//                if (StringUtils.isNotBlank(
//                        vo.getParentResourceNo()) &&
//                        vo.getParentResourceNo().equals(dto.getParentResourceNo())
//                        && StringUtils.isNotBlank(vo.getResourceType())
//                        && vo.getResourceType().equals(dto.getResourceType())) {
//                    resultList.add(vo);
//                }
//            }
            // 使用Lambda实现
             List<ResourceVo> resultList = list.stream()
                     .filter(vo -> StringUtils.isNotBlank(vo.getParentResourceNo()) &&
                             vo.getParentResourceNo().equals(dto.getParentResourceNo())
                             && StringUtils.isNotBlank(vo.getResourceType())
                             && vo.getResourceType().equals(dto.getResourceType()))
                     .collect(Collectors.toList());
            // 如果有数据,就直接返回
            return resultList;
        } else {
            // 如果没有数据, 就去查询数据库
            // 把数据库的结果,放入人redis
            log.info("redis数据为空,需要去数据库查询");
            ResourceVo bean = BeanUtil.toBean(dto, ResourceVo.class);
            List<ResourceVo> voList = resourceMapper.selectByCondition(bean);
            redisTemplate.opsForValue().set("resourceList", JSONUtil.toJsonStr(voList));
            return voList;
        }
    }*/

    @Override
    @Cacheable(value = CacheConstant.RESOURCE_LIST ,key ="#dto.hashCode()")
    public List<ResourceVo> listResources(ResourceDto dto) {
        ResourceVo bean = BeanUtil.copyProperties(dto, ResourceVo.class);
        List<ResourceVo> voList = resourceMapper.selectByCondition(bean);
        return voList;
    }

    @Override
    @Cacheable(value = CacheConstant.RESOURCE_TREE,key ="#treeItemVo.hashCode()")
    public TreeVo findResourceTree(TreeItemVo treeItemVo) {

            //创建根菜单
            TreeItemVo rootItem = new TreeItemVo(SuperConstant.ROOT_PARENT_ID, "智慧养老院", new ArrayList<TreeItemVo>());
            ResourceDto resourceDto = new ResourceDto();
            resourceDto.setResourceType(SuperConstant.MENU);
            //从数据库中查询菜单, 不要在循环中查询数据,一次性把数据查询出来,在Java内存中处理数据
            ResourceVo bean = BeanUtil.toBean(resourceDto, ResourceVo.class);
            List<ResourceVo> voList = resourceMapper.selectByCondition(bean);

            //使用递归进行树结构
            createTree(voList, rootItem);

            List<TreeItemVo> list = new ArrayList<>();
            list.add(rootItem);
            TreeVo treeVo = new TreeVo(list);
            return treeVo;
    }

    /**@Override
    public TreeVo findResourceTree(TreeItemVo treeItemVo) {
        String jsonStr = redisTemplate.opsForValue().get("resourceTree");
        if (StringUtils.isNotBlank(jsonStr)) {
            log.info("redis数据不为空");
            return JSONUtil.toBean(jsonStr, TreeVo.class);
        } else {
            log.info("redis数据为空,需要去数据库查询");
            //创建根菜单
            TreeItemVo rootItem = new TreeItemVo(SuperConstant.ROOT_PARENT_ID, "智慧养老院", new ArrayList<TreeItemVo>());
            ResourceDto resourceDto = new ResourceDto();
            resourceDto.setResourceType(SuperConstant.MENU);
            //从数据库中查询菜单, 不要在循环中查询数据,一次性把数据查询出来,在Java内存中处理数据
            ResourceVo bean = BeanUtil.toBean(resourceDto, ResourceVo.class);
            List<ResourceVo> voList = resourceMapper.selectByCondition(bean);

            //使用递归进行树结构
            createTree(voList, rootItem);

            List<TreeItemVo> list = new ArrayList<>();
            list.add(rootItem);
            TreeVo treeVo = new TreeVo(list);
            redisTemplate.opsForValue().set("resourceTree", JSONUtil.toJsonStr(treeVo));
            return treeVo;
        }
    }*/

    @Override
    public void addResources(Resource resource) {
//        查询父级数据
        Resource parent = resourceMapper.selectByResourceNo(resource.getParentResourceNo());
//        判断状态是否与父级一致
        if (!resource.getDataState().equals(parent.getDataState())) {
//            与父级状态不一致,抛异常
            throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
        }

//      判断父级的编号最后3位是000
        if (parent.getResourceType().equals("m") && !parent.getResourceNo().endsWith("000")) {
//            如果是菜单,最后的3位应该都是0
            throw new BaseException(BasicEnum.BAD_MENU_NO);
        }
//        生成编号
//        根据父编号 查询 子菜单集合 根据编号倒叙排序   100001002002 100001002001
        List<Resource> resourceList = resourceMapper.selectResourceByParentNo(resource.getParentResourceNo());
        String no = "";
        if (CollectionUtil.isEmpty(resourceList)) {
//             如果没有子菜单,直接生成
            no = NoProcessing.createNo(resource.getParentResourceNo(), false);
        } else {
//             如果有子菜单,在最大编号的基础上进行追加
            no = NoProcessing.createNo(resourceList.get(0).getResourceNo(), true);
        }
        /** 问题记录
         if (resource.getResourceType().equals("m") && !no.endsWith("000")){
         // 如果是菜单,最后的3位应该都是0
         throw new BaseException(BasicEnum.BAD_MENU_NO);
         }*/
        log.info("no={}", no);
//        保存
        resource.setResourceNo(no);
        resourceMapper.insert(resource);
        // 删除redis
        redisTemplate.delete("resourceTree");
        // 删除redis 资源对应的缓存 需要删除 key 通用操作
        redisTemplate.delete("resourceList");
    }

    @Override
    public List<MenuVo> menus() {
        // 获取当前用户
        Long userId = UserThreadLocal.getMgtUserId();
        log.info("userId:{}", userId);
        // 查询用户的菜单信息
        List<MenuVo> menuVoList = resourceMapper.selectResourceByuserId(userId);
        log.info("menuVoList:{}", menuVoList);
        // TODO 处理菜单之间的父子关系
        // 获取到所有的父菜单, 以及它的子菜单集合, Map<parentNo, List<MenuVo>>
        /*Map<String, List<MenuVo>> map = new HashMap<>();
        for (MenuVo menuVo : menuVoList) {
            // 获取到当前菜单的编号
            String resourceNo = menuVo.getResourceNo();
            // 遍历voList, 获取到当前菜单的子菜单
            for (MenuVo vo : menuVoList) {
                // 判断是否是当前菜单的子菜单
                boolean b = resourceNo.equals(vo.getParentResourceNo());
                if (b){
                    // 判断父菜单是否已经存在
                    if (map.get(resourceNo)!=null && map.get(resourceNo).size()>0){
                        // 父菜单存在
                        map.get(resourceNo).add(vo);
                    }else {
                        // 父菜单不存在
                        List<MenuVo> list = new ArrayList<>();\
                        list.add(vo);
                        map.put(resourceNo,list);
                    }
                }
            }
        }*/
        // 使用stream流对菜单列表进行处理，根据父资源编号进行分组，以便后续处理父子关系
        Map<String, List<MenuVo>> map = menuVoList.stream()
                .collect(Collectors.groupingBy(MenuVo::getParentResourceNo));
        log.info("map:{}", map);
        // 遍历菜单列表，对每个菜单项进行设置，包括重定向地址和meta信息，并处理子菜单
        for (MenuVo menuVo : menuVoList) {
            // 设置菜单的重定向地址为菜单名称的路径
            menuVo.setRedirect("/" + menuVo.getName());
            // 初始化菜单的meta信息
            menuVo.setMeta(new MenuMetaVo(menuVo.getName(), null, null));
            // 获取当前菜单的资源编号
            String resourceNo = menuVo.getResourceNo();
            // 根据当前菜单的资源编号，从map中获取对应的子菜单列表
            List<MenuVo> childrenList = map.get(resourceNo);
            // 如果子菜单列表不为空，则设置当前菜单的子菜单
            if (CollectionUtil.isNotEmpty(childrenList)) {
                childrenList.forEach(item -> {
                    // 设置子菜单的重定向地址为子菜单名称的路径
                    item.setRedirect(menuVo.getRedirect()+"/" + item.getName());
                    // 设置子菜单的meta信息
                    item.setMeta(new MenuMetaVo(item.getName(), null, null));
                });
                menuVo.setChildren(childrenList);
            }
        }
        // 获取根节点
        List<MenuVo> menuVos = map.get(SuperConstant.ROOT_PARENT_ID);
        log.info("menuVos:{}", menuVos);
        // 返回根节点
        return menuVos;
    }

    @Override
    public List<String> findAllButResource() {
        return resourceMapper.selectAllButResource();
    }

    /**
     * 使用递归处理volist 构建TreeSet结构
     *
     * @param voList
     * @param rootItem
     */
    private void createTree(List<ResourceVo> voList, TreeItemVo rootItem) {
        for (ResourceVo vo : voList) {
            if (vo.getParentResourceNo().equals(rootItem.getId()) && vo.getResourceNo().endsWith("000")) {
                // 创建当前孩子节点
                TreeItemVo item = new TreeItemVo(vo.getResourceNo(), vo.getResourceName(), new ArrayList<TreeItemVo>());
                // 把孩子节点放入父节点的孩子集合中
                rootItem.getChildren().add(item);
                //用户当前的孩子节点作为父节点, 查询他的孩子节点
                createTree(voList, item);
            }
        }
        log.info("rootItem:{}", rootItem);
    }

    public List<String> findButtonResourceByUserId(Long userVoId) {
        return resourceMapper.findButtonResourceByUserId(userVoId);
    }
}
